package com.jingxuan.simulation;

import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

import java.time.Duration;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class ApiLoadSimulation extends Simulation {

    // HTTP Protocol Configuration
    private HttpProtocolBuilder httpProtocol = http
        .baseUrl("http://localhost:8080/api")
        .acceptHeader("application/json")
        .contentTypeHeader("application/json")
        .userAgentHeader("Gatling Load Test");

    // Custom Feeder for dynamic users
    private Iterator<Map<String, Object>> userFeeder = Stream.generate((Supplier<Map<String, Object>>) () -> {
        String randomSuffix = String.valueOf(10000000 + new Random().nextInt(90000000));
        String phone = "139" + randomSuffix;
        String userName = "User" + randomSuffix;
        return Map.of(
            "phone", phone,
            "userName", userName,
            "password", "123456"
        );
    }).iterator();

    // Scenario Definition
    private ScenarioBuilder scn = scenario("Jingxuan API Load Test")
        .feed(userFeeder)
        
        // 1. Register (dynamic user)
        .exec(http("User Register")
            .post("/users")
            .body(StringBody("{\"userName\":\"#{userName}\", \"password\":\"#{password}\", \"phone\":\"#{phone}\"}"))
            .check(status().in(200, 400)) // 400 is acceptable if user exists (though unlikely with random)
        )
        .pause(1)

        // 2. Login
        .exec(http("User Login")
             .post("/auth/login")
             .body(StringBody("{\"phone\":\"#{phone}\", \"password\":\"#{password}\"}"))
             .check(status().is(200))
             .check(jsonPath("$.code").is("0"))
             .check(jsonPath("$.data.token").saveAs("token"))
        )
        .exitHereIfFailed()
        .pause(1)
        
        // 3. Recommend Products
        .exec(http("Get Recommend Products")
            .get("/recommend/products")
            .queryParam("limit", "20")
            .header("Authorization", "Bearer #{token}") 
            .check(status().is(200))
        )
        .pause(Duration.ofMillis(500), Duration.ofMillis(1500)) 

        // 4. Rank APIs
        .exec(http("Get Recommend Rank")
            .get("/rank/recommend")
            .header("Authorization", "Bearer #{token}")
            .check(status().is(200))
        )
        .pause(Duration.ofMillis(500), Duration.ofMillis(1000))
        
        .exec(http("Get Value Rank")
            .get("/rank/value")
            .header("Authorization", "Bearer #{token}")
            .check(status().is(200))
        )
        .pause(Duration.ofMillis(500), Duration.ofMillis(1000))
        
        .exec(http("Get New Rank")
            .get("/rank/new-product")
            .header("Authorization", "Bearer #{token}")
            .check(status().is(200))
        );

    // Injection Profile
    {
        setUp(
            scn.injectOpen(
                rampUsers(10).during(Duration.ofSeconds(10)), // Ramp up to 10 users in 10s
                constantUsersPerSec(2).during(Duration.ofSeconds(20)) // Hold 2 users/sec
            )
        ).protocols(httpProtocol);
    }
}
